package org.wheel.plugins.toolkit.sql.capability;

import org.wheel.plugins.toolkit.sql.core.AbstractWrapper;
import org.wheel.plugins.toolkit.sql.enums.SqlFunction;
import org.wheel.plugins.toolkit.sql.enums.SqlTimeUnit;
import org.wheel.plugins.toolkit.sql.function.FunctionBuilder;
import org.wheel.plugins.toolkit.sql.helper.LambdaUtils;
import org.wheel.plugins.toolkit.sql.helper.SFunction;

/**
 * 标量函数能力
 * @param <W> 子类型
 * @param <T> 主实体
 */
public interface LambdaScalar<W extends LambdaScalar<W,T>, T> {

    /* ================== 日期函数 ================== */
    default W dateAdd(SFunction<T,?> col, int amount, SqlTimeUnit unit){
        return dateAdd(col, amount, unit, col);
    }
    default W dateAdd(SFunction<T,?> col, int amount, SqlTimeUnit unit, String columnAlias){
        return function(scalar(SqlFunction.DATE_ADD.name(), columnAlias)
                .col(LambdaUtils.getColumn(col))
                .arg(amount)
                .col(unit));
    }
    default <R> W dateAdd(SFunction<T,?> col, int amount, SqlTimeUnit unit, SFunction<R,?> columnAlias){
        Class<?> entityClass = LambdaUtils.getCapturingClass(col);
        Class<?> columnClass = LambdaUtils.getCapturingClass(columnAlias);
        String columnName = LambdaUtils.getFieldName(columnAlias);
//        String columnPrefix = null;
//        if(entityClass != columnClass){
//            columnPrefix = LambdaUtils.getFieldName(columnAlias);
//        }
//        String columnAliasJoin = StrUtil.isBlank(columnPrefix)? columnName : StrUtil.join(".",  columnPrefix, columnName);
        return dateAdd(col, amount, unit, columnName);
    }

    default W dateDiff(SFunction<T,?> col1, SFunction<T,?> col2, String columnAlias){
        return function(scalar(SqlFunction.DATE_DIFF.name(), columnAlias)
                .col(LambdaUtils.getColumn(col1))
                .col(LambdaUtils.getColumn(col2)));
    }
    default W dateDiff(SFunction<T,?> col1, SFunction<T,?> col2){
        return dateDiff(col1, col2, null);
    }

    /* ================== 字符串函数 ================== */
    default W concat(SFunction<T,?> col, String concatStr, String columnAlias){
        return function(scalar(SqlFunction.CONCAT.name(), columnAlias)
                .col(LambdaUtils.getColumn(col))
                .arg(concatStr));
    }
    default W concat(SFunction<T,?> col, String concatStr){
        return concat(col, concatStr, null);
    }

    default W substring(SFunction<T,?> col, int start, int len, String columnAlias){
        return function(scalar(SqlFunction.SUBSTRING.name(), columnAlias)
                .col(LambdaUtils.getColumn(col))
                .arg(start)
                .arg(len));
    }
    default W substring(SFunction<T,?> col, int start, int len){
        return substring(col, start, len, null);
    }

    /* ================== JSON 函数 ================== */
    default W jsonExtract(SFunction<T,?> col, String jsonPath, String columnAlias){
        return function(scalar(SqlFunction.JSON_EXTRACT.name(), columnAlias)
                .col(LambdaUtils.getColumn(col))
                .arg(jsonPath));
    }
    default W jsonExtract(SFunction<T,?> col, String jsonPath){
        return jsonExtract(col, jsonPath, null);
    }

    /* ================== 数学函数 ================== */
    default W abs(SFunction<T,?> col, String columnAlias){
        return function(scalar("abs", columnAlias).col(LambdaUtils.getColumn(col)));
    }
    default W abs(SFunction<T,?> col){
        return abs(col, null);
    }

    default W round(SFunction<T,?> col, int scale, String columnAlias){
        return function(scalar("round", columnAlias)
                .col(LambdaUtils.getColumn(col))
                .arg(scale));
    }
    default W round(SFunction<T,?> col, int scale){
        return round(col, scale, null);
    }

    /* ================== 通用标量工厂 ================== */
    private FunctionBuilder scalar(String pluginKey, String columnAlias){
        return FunctionBuilder.plugin(pluginKey, null)
                .as(columnAlias)
                .bind((AbstractWrapper<?, ?>) this);
    }

    /* ================== 原子方法 ================== */
    W function(FunctionBuilder fn);
}